/*
----------------------------------------------------------------------------------------------------
This source file is part of the Gamut Framework
Copyright (c) 2007 by Ryan Holcombe

This program is free software; you can redistribute it and/or modify it under the terms of the GNU
Lesser General Public License as published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
----------------------------------------------------------------------------------------------------
*/


#ifndef _StateManager_h_
#define _StateManager_h_

#include "GamutIManager.h"
#include <boost/ptr_container/ptr_map.hpp>
#include <vector>
#include <list>



namespace Gamut
{

	/**
 		StateManager handles all the app states. States are registered, then if loaded are pushed to the top
		of the stack and run each frame. States are put into a pause state when another state is pushed
		on top of the stack
	*/

	class IState;
	
	typedef boost::ptr_map<std::string, IState> StateMap;
	typedef std::list<IState*> StateList;
	typedef std::vector<std::string> UpdateList;


	class StateManager : public IManager
	{
	private:
		StateMap mStateMap;				//!< map of attached components
		StateList mStack;				//!< stack of IState pointers
		UpdateList mPush;				//!< list of states that need to be pushed during tick()
		UpdateList mPop;				//!< list of states that need to be popped during tick()		

	public:
		/** Default constructor
		*/
		StateManager(const std::string& name, unsigned int priority);
	
	
		/** Default deconstructor
			\brief destroys any registered states and removes them from the queue
		*/
		virtual ~StateManager();

		/**
 			\brief loads the state in the map
			\remarks all states must be registered before they can be pushed onto the stack
			\remark if the state is already on the stack, it will push it to the top
			\param[in] name what to call the state
			\param[in] state pointer to the IState object
		*/
		virtual void registerState(std::string name, IState *state);
		
		
		/**
 			\brief removes the state from the stack and from the map
			\remarks all states must be registered before they can be pushed onto the stack
			\param[in] name what the state is called
		*/
		virtual void destroyState(std::string name);
		
		
		/**
 			\brief adds a state to the list to be pushed next frame
			\param[in] name what the state is called
		*/
		virtual void push(std::string name);
		
		
		/**
 			\brief adds a state to the list to be popped next frame
			\param[in] name what the state is called
		*/
		virtual void pop(std::string name);
		
		
		/**
			\brief runs the top state in tick mode and every other state on the stack in pause mode
			\param[in] elapsed time in seconds since the last frame
			\remarks
				if _DEBUG is enabled, tick will profile each state on the stack
		*/
		virtual void tick(double elapsed);
		
		
		/**
			\brief is a state on the stack?
			\param[in] name string assigned to the state
			\return 1 if the state is on the stack, 0 otherwise
		*/
		bool onStack(std::string name);
		
		
		/**
			\brief finds the name of an item on the stack
			\remarks internal function
			\param[in] state pointer to an IState object
			\return the name of the state, or "" if it cannot be found
		*/
		std::string _getName(IState *state);
		
		
		/**
			\brief returns the size of the stack
			\return the number of IStates on the stack
		*/
		int stackSize() { return mStack.size(); }
		
		
	protected:
		/**
 			\brief pushes a registered state onto the stack
			\remarks if the state is already on the stack, it will push it to the top
			\param[in] name what the state is called
		*/
		void _pushState(std::string name);
		
		
		/**
 			\brief will pop a state from the stack
			\remarks
				works a little differently from a normal stack, this will pop a state
				from anywhere on the stack
			\param[in] name string assigned to the state
		*/		
		void _popState(std::string name);
		
		
		/**
 			\brief will pop a state from the stack
			\param[in] state pointer to a state
		*/		
		void _popState(IState *state);
	};
	
}



#endif
